package com.ffmpeg.opt.controller;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.ffmpeg.opt.common.ffmpeg.FmpegUtil;
import com.ffmpeg.opt.common.ffmpeg.handler.MovieTask;
import com.ffmpeg.opt.domain.CallBackResp;
import com.ffmpeg.opt.domain.DurationParam;
import com.ffmpeg.opt.domain.OperationRequestParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

/**
 * 操作fmpeg命令
 */
@RestController
@RequestMapping("/api")
@Slf4j
public class ApiController {

    public static final FmpegUtil fmpegUtil = new FmpegUtil();

    public static final String ffmpeg = "ffmpeg";

    /**
     * 操作命令
     */
    @ApiOperation("执行ffmpeg批命令")
    @PostMapping("/operation")
    public ResponseEntity operation(@RequestBody OperationRequestParam param) {
        new Thread(() -> {
            long startTime = System.currentTimeMillis();
            boolean success = true;
            try {
                OperationRequestParam.CommandDesc[] commands = param.getCommands();
                // 1.拿到命令先获取时长
                DurationParam durationParam = new DurationParam();
                durationParam.setResourcePath(param.getResourcePath());
                durationParam.setTaskId(param.getTaskId());
                Long duration = duration(durationParam).getBody();
                // 2.时长获取后，走其他命令
                for (int i = 0, j = 1; i < commands.length; i++, j++) {
                    log.info("步骤{}：开始", j);
                    OperationRequestParam.CommandDesc commandDesc = commands[i];
                    executeCommond(param.getTaskId(), "[ " + param.getTaskDesc() + " ]步骤" + j + "：" + commandDesc.getName(), commandDesc.getCommand(), duration);
                    log.info("步骤{}：结束", j);
                    ThreadUtil.sleep(500);
                }
            } catch (Exception e) {
                log.error(ExceptionUtil.stacktraceToString(e));
                success = false;
            } finally {
                // 3.回调
                long endTime = System.currentTimeMillis();
                String callBackUrl = param.getCallBackUrl();
                if (StrUtil.isNotBlank(callBackUrl)) {
                    CallBackResp callBackResp = new CallBackResp();
                    callBackResp.setExt(param.getExt());
                    callBackResp.setTaskId(param.getTaskId());
                    callBackResp.setTime(endTime - startTime);
                    callBackResp.setSuccess(success);
                    String post = HttpUtil.post(callBackUrl, JSONUtil.toJsonStr(callBackResp));
                    log.info("回调结果:{}", post);
                }
            }
        }).start();
        return ResponseEntity.ok().build();
    }

    /**
     * 查询任务进度
     */
    @ApiOperation("查询批命令的执行进度")
    @GetMapping("/query/{taskIds}")
    public ResponseEntity<Map<String, String>> query(@PathVariable String[] taskIds) {
        Map<String, String> result = new HashMap<>();
        for (String taskId : taskIds) {
            result.put(taskId, fmpegUtil.queryProgress(taskId));
        }
        return ResponseEntity.ok(result);
    }

    /**
     * 默认回调结果，测试用
     */
    @PostMapping("/callback")
    public ResponseEntity<String> callbackDefault(@RequestBody String json) {
        log.info("成功处理回调结果:{}", json);
        return ResponseEntity.ok(json);
    }

    /**
     * 获取视频时长
     */
    @ApiOperation("查询视频的时长")
    @GetMapping("/duration")
    public ResponseEntity<Long> duration(DurationParam param) {
        long startTime = System.currentTimeMillis();
        log.info("获取视频时长");
        String commond = ffmpeg + " -i " + param.getResourcePath();
        MovieTask build = MovieTask.build(param.getTaskId(), "初始：获取时长", null);
        fmpegUtil.start(commond, build);
        Long duration = null;
        while (duration == null) {
            duration = build.getDuration();
            log.info("正在获取时长....");
            ThreadUtil.sleep(1000);
        }
        log.info("获取视频时长结束：{}", duration);
        fmpegUtil.waitDone(param.getTaskId());
        ThreadUtil.sleep(500);
        fmpegUtil.stop(param.getTaskId());
        // 3.回调
        long endTime = System.currentTimeMillis();
        String callBackUrl = param.getCallBackUrl();
        if (StrUtil.isNotBlank(callBackUrl)) {
            CallBackResp callBackResp = new CallBackResp();
            callBackResp.setExt(param.getExt());
            callBackResp.setTaskId(param.getTaskId());
            callBackResp.setTime(endTime - startTime);
            callBackResp.setSuccess(true);
            String post = HttpUtil.post(callBackUrl, JSONUtil.toJsonStr(callBackResp));
            log.info("回调结果:{}", post);
        }
        return ResponseEntity.ok(duration);
    }

    /**
     * 执行命令
     *
     * @param taskId   任务ID
     * @param taskDesc 任务描述
     * @param commond  命令
     * @param duration 时长
     */
    public void executeCommond(String taskId, String taskDesc, String commond, Long duration) {
        log.info(taskDesc + "开始");
        MovieTask build = MovieTask.build(taskId, taskDesc, duration);
        fmpegUtil.start(commond, build);
        fmpegUtil.waitDone(taskId);
        ThreadUtil.sleep(500);
        fmpegUtil.stop(taskId);
        log.info(taskDesc + "结束");
    }

}
